﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Text;
using System;

namespace K9Tools.Abstractions.Extensions;

public static class StringExtensions
{
    public static string ToSnakeCase(this string camelCase)
    {
        var sb = new StringBuilder();
        sb.Append(char.ToLower(camelCase[0]));
        for (var i = 1; i < camelCase.Length; i++)
        {
            if (char.IsUpper(camelCase[i]))
            {
                sb.Append("_" + char.ToLower(camelCase[i]));
            }
            else
            {
                sb.Append(camelCase[i]);
            }
        }
        return sb.ToString();
    }

    public static string EnsureNotEndWith(this string raw, char c, bool ignoreCase = true)
    {
        if (raw[^1] == c || ignoreCase && raw[^1] == char.ToUpper(c))
        {
            return raw.Remove(raw.Length - 1);
        }
        return raw;
    }

    /// <summary>
    /// 单词变成单数形式
    /// </summary>
    /// <param name="word"></param>
    /// <returns></returns>
    public static string ToSingular(this string word)
    {
        var regs = new[]
        {
                new KeyValuePair<string, string>("${keep}y", "(?<keep>[^aeiou])ies$"),
                new KeyValuePair<string, string>("${keep}", "(?<keep>[aeiou]y)s$"),
                new KeyValuePair<string, string>("${keep}", "(?<keep>[sxzh])es$"),
                new KeyValuePair<string, string>("${keep}", "(?<keep>[^sxzhyu])s$")
            };

        foreach (var r in regs)
        {
            var regex = new Regex(r.Value);
            if (regex.IsMatch(word))
            {
                return regex.Replace(word, r.Key);
            }
        }

        return word;
    }
    /// <summary>
    /// 单词变成复数形式
    /// </summary>
    /// <param name="word"></param>
    /// <returns></returns>
    public static string ToPlural(this string word)
    {
        var regs = new[]
        {
                new KeyValuePair<string, string>("${keep}ies", "(?<keep>[^aeiou])y$"),
                new KeyValuePair<string, string>("${keep}s", "(?<keep>[aeiou]y)$"),
                new KeyValuePair<string, string>("${keep}es", "(?<keep>[sxzh])$"),
                new KeyValuePair<string, string>("${keep}s", "(?<keep>[^sxzhy])$")
            };

        foreach (var r in regs)
        {
            Regex.Replace(word, r.Value, r.Key);
        }

        return word;
    }

    public static string F(this string template, params object[] args)
    {
        return string.Format(template, args);
    }

    public static string RemovePreFix(this string str, params string[] preFixes)
    {
        if (string.IsNullOrEmpty(str))
        {
            return string.Empty;
        }

        if (preFixes.Length == 0)
        {
            return str;
        }

        foreach (var preFix in preFixes)
        {
            if (str.StartsWith(preFix))
            {
                return str.Right(str.Length - preFix.Length);
            }
        }

        return str;
    }

    public static string Right(this string str, int len)
    {
        if (str == null)
        {
            throw new ArgumentNullException(nameof(str));
        }

        if (str.Length < len)
        {
            throw new ArgumentException("len argument can not be bigger than given string's length!");
        }

        return str.Substring(str.Length - len, len);
    }

    public static string Left(this string str, int len)
    {
        if (str == null)
        {
            throw new ArgumentNullException(nameof(str));
        }

        if (str.Length < len)
        {
            throw new ArgumentException("len argument can not be bigger than given string's length!");
        }

        return str.Substring(0, len);
    }

    public static string RemovePostFix(this string str, params string[] postFixes)
    {
        if (string.IsNullOrEmpty(str))
        {
            return string.Empty;
        }

        if (postFixes.Length == 0)
        {
            return str;
        }

        foreach (var postFix in postFixes)
        {
            if (str.EndsWith(postFix))
            {
                return str.Left(str.Length - postFix.Length);
            }
        }

        return str;
    }

    /// <summary>
    /// 简单模式匹配
    /// </summary>
    /// <param name="value"></param>
    /// <param name="pattern">支持a*,  *a, a*b</param>
    /// <param name="wildcard"></param>
    /// <returns></returns>
    public static bool WildcardMatch(this string value, string pattern, char wildcard = '*')
    {
        var parts = pattern.Split(new[] { wildcard }, StringSplitOptions.RemoveEmptyEntries);
        var toCheck = value;
        var start = 0;
        var end = parts.Length;

        if (!pattern.StartsWith(wildcard.ToString(CultureInfo.InvariantCulture)))
        {
            if (!toCheck.StartsWith(parts.First()))
                return false;

            start = 1;
        }

        if (!pattern.EndsWith(wildcard.ToString(CultureInfo.InvariantCulture)))
        {
            if (!toCheck.EndsWith(parts.Last()))
                return false;

            end--;
        }

        for (var i = start; i < end; i++)
        {
            var index = toCheck.IndexOf(parts[i], StringComparison.Ordinal);
            if (index < 0)
                return false;

            toCheck = toCheck[index..];
        }

        return true;
    }

    public static string ToBase64String(this string text)
    {
        if (string.IsNullOrEmpty(text)) return string.Empty;
        var data = Encoding.UTF8.GetBytes(text);
        return Convert.ToBase64String(data);
    }

    public static string FromBase64String(this string text)
    {
        if (string.IsNullOrEmpty(text)) return string.Empty;
        var data = Convert.FromBase64String(text);
        return Encoding.UTF8.GetString(data);
    }

    /// <summary>
    /// 检测字符串是否以数字开头
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    public static bool StartsWithDigital(this string text)
    {
        if (string.IsNullOrEmpty(text)) return false;
        return text[0] >= '0' && text[0] <= '9';
    }

    public static bool EqualsIgnoreCase(this string? text, string? other)
    {
        if(text == null && other == null) return true;
        if (text == null || other == null) return false;
        return text.Equals(other, StringComparison.InvariantCultureIgnoreCase);
    }
}